package com.ruoyi.web.task;

import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.sms.AliyunSmsService;
import com.ruoyi.web.domain.device.DeviceInfo;
import com.ruoyi.web.domain.insect.InsectRecord;
import com.ruoyi.web.domain.warning.*;
import com.ruoyi.web.enums.DeviceTypeEnum;
import com.ruoyi.web.enums.InsectWarningTypeEnum;
import com.ruoyi.web.middleware.influxdb.Influxdb2Service;
import com.ruoyi.web.pojo.request.insect.InsectHistoryDataRequest;
import com.ruoyi.web.service.device.DeviceInfoService;
import com.ruoyi.web.service.insect.InsectRecordService;
import com.ruoyi.web.service.warning.*;
import com.ruoyi.web.utils.email.MailService;
import com.ruoyi.web.utils.influxdb.DeviceData;
import com.ruoyi.web.utils.influxdb.DeviceHistoryDataParam;
import com.ruoyi.web.utils.v2.V2FactorInfo;
import com.ruoyi.web.utils.v2.V2RremoteCall;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.ruoyi.web.constant.WarningConstants.*;

@Component("warningTask")
public class WarningTask {

    @Autowired
    private WarningConfigService warningConfigService;

    @Autowired
    private DeviceInfoService deviceInfoService;

    @Autowired
    private Influxdb2Service influxdb2Service;

    @Autowired
    private WarningFactorRecordService warningRecordService;

    @Autowired
    private WarningInsectRecordService warningInsectRecordService;

    @Autowired
    private WarningInsectService warningInsectService;

    @Autowired
    private InsectRecordService insectRecordService ;

    @Autowired
    private WarningNoticeService warningNoticeService;

    @Autowired
    private WarningAddressBookService warningAddressBookService;

    @Autowired
    private MailService mailService;

    //warningTask.runInsect('200')
    public void runInsect(String params)
    {
        System.out.println("执行有参方法：" + params);
    }

    /**
     * @desc  传感器预警判断
     * @author fwx 2024/2/5 16:53
     **/
    public void runFactor()
    {
        //01 查询所有预警配置
        List<WarningConfig> configs = warningConfigService.queryAll();
        Map<String, List<WarningConfig>> configMap = configs.stream().collect(Collectors.groupingBy(WarningConfig::getFactorKey));

        //02 根据配置的因子 关联出因子下的设备,因子映射关系
        List<V2FactorInfo> factorKeyList = V2RremoteCall.getFactors();
        Map<Long, List<V2FactorInfo>> productFactor = factorKeyList.stream().collect(Collectors.groupingBy(V2FactorInfo::getProductId));

        //根据产品id查设备
        List<Long> productIds = factorKeyList.stream().map(V2FactorInfo::getProductId).collect(Collectors.toList());
        List<DeviceInfo> devices = deviceInfoService.getByProductId(productIds);

        //保存的预警
        List<WarningFactorRecord> addRecord = new ArrayList<>();

        //得到最新的预警记录
        List<WarningFactorRecord> newList = warningRecordService.getNewList();
        Map<String, WarningFactorRecord> recordMap = newList.stream()
                .collect(Collectors.toMap(rec -> rec.getDeviceId() + rec.getFactorKey() + rec.getConfigId(), Function.identity()));

        //03 预警判断
        for (DeviceInfo device : devices) {
            //查询设备的最新数据
            DeviceData deviceData = influxdb2Service.getLastMonitorDataMap(device.getDeviceId(), device.getProductId());

            List<V2FactorInfo> factors = productFactor.get(device.getProductId());

            for (V2FactorInfo factor : factors) {
                List<WarningConfig> factorConfig = configMap.get(factor.getFactorKey());

                if(factorConfig == null){
                    continue;
                }

                //查询设备对应的预警
                for (WarningConfig config : factorConfig) {

                    //判断重复预警
                    WarningFactorRecord rec = recordMap.get(device.getDeviceId() + factor.getFactorKey() + config.getId());
                    if(rec != null && ChronoUnit.MINUTES.between(rec.getWarningTime(),deviceData.getDataTime()) == 0){
                        System.err.println("该记录已经判断 -- ");
                        continue;
                    }

                    //查询设备下的传感器最新的预警
                    boolean flag ;//ture 表示发生预警
                    String modelKey = factor.getMetadataKey();
                    if(config.judgeTypeStr() == 0){
                        Double data = deviceData.getDouble(modelKey);
                        flag = config.judgeValueWarning(data);

                        System.err.println(String.format("要判断的值:%s , 判断条件: %s , 判断的类型: %d ,判断的因子: %s, 是否预警: %b "
                                , data+"" + "" , config.getJudgeValue(),config.getJudgeType(),config.getFactorKey(), flag));

                    }else {
                        //查询n天的数据
                        DeviceHistoryDataParam param = new DeviceHistoryDataParam(device.getDeviceId(), device.getProductId(), config.judgeTypeStr());
                        List<DeviceData> deviceHistory = influxdb2Service.getMonitorDataMapByTime(param);

                        //判断数据是否连续 是否符合条件
                        flag = config.judgeHistroyWarning(deviceHistory,modelKey);
                    }

                    //04 生成预警记录
                    if(flag){
                        WarningFactorRecord record = this.buildRecord(config,device,deviceData);
                        addRecord.add(record);
                    }

                }

            }
        }

        //保存记录并发送通知
        warningRecordService.insertList(addRecord);
        this.sendFactorNotice(addRecord);

    }


    public WarningFactorRecord buildRecord(WarningConfig config ,DeviceInfo device , DeviceData deviceData ){
        WarningFactorRecord record = new WarningFactorRecord();
        record.setFactorKey(config.getFactorKey());
        record.setWarningLevel(config.getWarningLevel());
        record.setFactorName(config.getFactorName());
        record.setConfigId(config.getId());
        record.setWarningContent(config.getWarningContent());
        record.setWarningRecommend(config.getWarningRecommend());
        record.setAbnormalValue(config.abnormalValue());
        record.setFactorType(config.getFactorType());
        record.setWarningName(config.getWarningName());

        record.setCrtTime(LocalDateTime.now());
        record.setWarningTime(deviceData.getDataTime());

        record.setDeviceId(device.getDeviceId());
        record.setDeviceName(device.getDeviceName());
        record.setProductId(device.getProductId());
        record.setDeviceType(device.getDeviceType());

        return record;
    }


    /**
     * @desc  昆虫预警判断
     * @author fwx 2024/2/5 16:53
     **/
    public void runInsect(){

        // 查询虫情设备
        List<DeviceInfo> devices = deviceInfoService.getAllDeviceByType(DeviceTypeEnum.FL2.getValue());
        List<String> deviceIds = devices.stream().map(DeviceInfo::getDeviceId).collect(Collectors.toList());
        //Map<String, DeviceInfo> deviceMap = devices.stream().collect(Collectors.toMap(DeviceInfo::getDeviceId, Function.identity()));

        // 查询启用的虫情预警配置
        List<WarningInsect> insects = warningInsectService.getEnabled();

        //识别记录 映射为 昆虫名 + 设备id
        Function<InsectRecord,String> recMapName = rec -> rec.getInsectName() + rec.getDeviceId();

        //今年的虫情数据
        List<InsectRecord> historyYearData = insectRecordService.getHistoryData(InsectHistoryDataRequest.getYear(deviceIds));
        Map<String, List<InsectRecord>> yearInsectMap = historyYearData.stream().collect(Collectors.groupingBy(recMapName));

        //本月的虫情数据
        List<InsectRecord> historyMonthData = insectRecordService.getHistoryData(InsectHistoryDataRequest.getMonth(deviceIds));
        Map<String, List<InsectRecord>> monthInsectMap = historyMonthData.stream().collect(Collectors.groupingBy(recMapName));

        //昨日的虫情数据
        List<InsectRecord> historyDayData = insectRecordService.getHistoryData(InsectHistoryDataRequest.getDay(deviceIds));
        Map<String, List<InsectRecord>> dayInsectMap = historyDayData.stream().collect(Collectors.groupingBy(recMapName));

        //始见期预警记录
        List<WarningInsectRecord> firstRecord = warningInsectRecordService.getByType(InsectWarningTypeEnum.FIRST.getValue());
        Set<String> firstSet = firstRecord.stream().map(rec -> rec.getInsectName() + rec.getDeviceId()).collect(Collectors.toSet());

        //预警判断逻辑
        List<WarningInsectRecord> addRecords = new ArrayList<>();

        for (WarningInsect insect : insects) {

            for (DeviceInfo device : devices) {
                //判断始见预警
                List<InsectRecord> year = yearInsectMap.get(insect.getInsectName() + device.getDeviceId());
                if(year != null){
                    //如果没有见过该虫 生产预警
                    if(!firstSet.contains(insect.getInsectName() + device.getDeviceId())){
                        WarningInsectRecord record = this.buildRecord(insect, device, InsectWarningTypeEnum.FIRST.getValue(), year.size());
                        addRecords.add(record);
                    }
                }

                //判断月高峰
                List<InsectRecord> month = monthInsectMap.get(insect.getInsectName() + device.getDeviceId());
                if(month != null){
                    int sum = month.stream().mapToInt(InsectRecord::getCount).sum();
                    if (insect.getPeakMonth() != null && sum >= insect.getPeakMonth()){
                        WarningInsectRecord record = this.buildRecord(insect, device, InsectWarningTypeEnum.MONTH.getValue(),sum);
                        addRecords.add(record);
                    }
                }

                //判断日高峰
                List<InsectRecord> day = dayInsectMap.get(insect.getInsectName() + device.getDeviceId());
                if(day != null){
                    int sum = day.stream().mapToInt(InsectRecord::getCount).sum();
                    if (insect.getPeakDay() != null && sum >= insect.getPeakDay()){
                        WarningInsectRecord record = this.buildRecord(insect, device, InsectWarningTypeEnum.DAY.getValue(),sum);
                        addRecords.add(record);
                    }
                }

            }
        }

        System.err.println("新增预警:" + addRecords.size());
        warningInsectRecordService.insertList(addRecords);
        this.sendInsectNotice(addRecords);
    }

    //type 预警类型 value 发现的昆虫数量
    public WarningInsectRecord buildRecord(WarningInsect insect,DeviceInfo deviceInfo ,Integer type , Integer value){
        WarningInsectRecord record = new WarningInsectRecord();

        record.setInsectCode(insect.getInsectCode());
        record.setInsectName(insect.getInsectName());
        record.setInsectType(insect.getInsectType());

        record.setInsectWarningType(type);
        record.setWarningValue(value);

        if(InsectWarningTypeEnum.DAY.getValue().equals(type)){
            record.setWarningJudgeValue(insect.getPeakDay());
        }

        if(InsectWarningTypeEnum.MONTH.getValue().equals(type)){
            record.setWarningJudgeValue(insect.getPeakMonth());
        }

        if(InsectWarningTypeEnum.FIRST.getValue().equals(type)){
            record.setWarningJudgeValue(0);
        }

        record.setCrtTime(LocalDateTime.now());
        record.setWarningTime(LocalDateTime.now());

        record.setDeviceName(deviceInfo.getDeviceName());
        record.setDeviceId(deviceInfo.getDeviceId());

        return record;
    }

    public void sendFactorNotice(List<WarningFactorRecord> records){

        if(CollectionUtils.isEmpty(records)){
            return;
        }

        String onePhone = this.getNoticeSmsByLevel(LEVEL_ONE);
        String twoPhone = this.getNoticeSmsByLevel(LEVEL_TWO);
        String threePhone = this.getNoticeSmsByLevel(LEVEL_THREE);

        String oneEmail = this.getNoticeEmailByLevel(LEVEL_ONE);
        String twoEmail = this.getNoticeEmailByLevel(LEVEL_TWO);
        String threeEmail = this.getNoticeEmailByLevel(LEVEL_THREE);

        System.err.println("1 手机号: " + onePhone);
        System.err.println("2 手机号: " + twoPhone);
        System.err.println("3 手机号: " + threePhone);
        System.err.println("1 邮箱: " + oneEmail);
        System.err.println("2 邮箱: " + twoEmail);
        System.err.println("3 邮箱: " + threeEmail);

        for (WarningFactorRecord record : records) {
            String content = record.buildEmailContent();

            JSONObject json = new JSONObject();
            json.put("time", DateUtils.formatDateTime(record.getWarningTime()));
            json.put("deviceName", record.getDeviceName());
            json.put("deviceNo", record.getDeviceId());
            json.put("wname", record.getWarningName());
            json.put("wlevel",record.getWarningLevel());
            json.put("content",record.getAbnormalValue());

            if(Objects.equals(record.getWarningLevel(), LEVEL_ONE)){
                mailService.sendSimpleMail(oneEmail,"灾情报警",content);
                AliyunSmsService.sendFactorWarning(onePhone,json);
            }

            if(Objects.equals(record.getWarningLevel(), LEVEL_TWO)){
                mailService.sendSimpleMail(twoEmail,"灾情报警",content);
                AliyunSmsService.sendFactorWarning(twoPhone,json);
            }

            if(Objects.equals(record.getWarningLevel(), LEVEL_THREE)){
                mailService.sendSimpleMail(threeEmail,"灾情报警",content);
                AliyunSmsService.sendFactorWarning(threePhone,json);
            }
        }
    }

    /**
     * @desc  得到某一等级预警通知的手机号
     * @author fwx 2024/2/21 11:51
     **/
    public String getNoticeSmsByLevel(String level){
        List<WarningNotice> warningNotices = warningNoticeService.queryAll();

        String smsBookIds = warningNotices.stream()
                .filter(notice -> notice.getWarningType().contains(WARNING_TYPE_FACTOR))
                .filter(notice -> notice.getWarningLevel().contains(level))
                .filter(notice -> notice.getIsSms() == 0)
                .map(WarningNotice::getBookId)
                .collect(Collectors.joining(","));

        List<String> smsBookIdList = Arrays.asList(smsBookIds.split(","));

        //发送短信的手机号
        String insectPhone = this.getContact(smsBookIdList,WarningAddressBook::getContactPhone);

        return insectPhone;
    }

    /**
     * @desc  筛选联系人
     * @author fwx 2024/2/21 13:55
     **/
    public String getContact(List<String> smsBookIdList,Function<WarningAddressBook,String> function){
        //获取联系人
        List<WarningAddressBook> addressBooks = warningAddressBookService.queryAll();

        //发送短信的手机号
        String insectPhone = null;

        if(smsBookIdList.contains("all")){
            System.err.println("短信发送所有人");
            insectPhone = addressBooks.stream()
                    .map(function)
                    .collect(Collectors.joining(","));
        }else {
            insectPhone = addressBooks.stream()
                    .filter(book -> smsBookIdList.contains(book.getId().toString()))
                    .map(function)
                    .collect(Collectors.joining(","));
        }

        return insectPhone;
    }

    /**
     * @desc  得到某一等级预警通知的邮箱
     * @author fwx 2024/2/21 11:51
     **/
    public String getNoticeEmailByLevel(String level){
        List<WarningNotice> warningNotices = warningNoticeService.queryAll();

        String emailBookIds = warningNotices.stream()
                .filter(notice -> notice.getWarningType().contains(WARNING_TYPE_FACTOR))
                .filter(notice -> notice.getWarningLevel().contains(level))
                .filter(notice -> notice.getIsEmail() == 0)
                .map(WarningNotice::getBookId)
                .collect(Collectors.joining(","));

        List<String> emailBookIdList = Arrays.asList(emailBookIds.split(","));

        //发送的邮箱
        String insectEmail = this.getContact(emailBookIdList,WarningAddressBook::getContactEmail);

        return insectEmail;
    }


    /**
     * @desc  发送虫情预警
     * @author fwx 2024/2/21 14:06
     **/
    public void sendInsectNotice(List<WarningInsectRecord> addRecords){

        if(CollectionUtils.isEmpty(addRecords)){
            return;
        }

        List<WarningNotice> warningNotices = warningNoticeService.queryAll();

        //虫情预警通知
        List<WarningNotice> insectEmailNotices = warningNotices.stream()
                .filter(notice -> notice.getWarningType().contains(WARNING_TYPE_INSECT))
                .filter(notice -> notice.getIsEmail() == 0)
                .collect(Collectors.toList());

        List<WarningNotice> insectSmsNotices = warningNotices.stream()
                .filter(notice -> notice.getWarningType().contains(WARNING_TYPE_INSECT))
                .filter(notice -> notice.getIsSms() == 0)
                .collect(Collectors.toList());

        String emailBookIds = insectEmailNotices.stream().map(WarningNotice::getBookId).collect(Collectors.joining(","));
        List<String> emailBookIdList = Arrays.asList(emailBookIds.split(","));

        String smsBookIds = insectSmsNotices.stream().map(WarningNotice::getBookId).collect(Collectors.joining(","));
        List<String> smsBookIdList = Arrays.asList(smsBookIds.split(","));

        //发送虫情短信的手机号
        String insectPhone = this.getContact(smsBookIdList,WarningAddressBook::getContactPhone);

        //发送虫情邮箱地址
        String insectEmail = this.getContact(emailBookIdList,WarningAddressBook::getContactEmail);;

        System.err.println("手机号: " + insectPhone);
        System.err.println("邮箱: " + insectEmail);

        for (WarningInsectRecord record : addRecords) {
            //发送短信
            if(StringUtils.isNotBlank(insectPhone)){
                JSONObject json = new JSONObject();
                json.put("time", DateUtils.formatDateTime(record.getWarningTime()));
                json.put("deviceName", record.getDeviceName());
                json.put("deviceNo", record.getDeviceId());
                json.put("InsectName", record.getInsectName());
                json.put("num",record.getWarningValue());

                if(InsectWarningTypeEnum.FIRST.getValue().equals(record.getInsectWarningType())){
                    AliyunSmsService.sendInsectFirst(insectPhone,json);
                }

                if(InsectWarningTypeEnum.DAY.getValue().equals(record.getInsectWarningType())){
                    AliyunSmsService.sendInsectDay(insectPhone,json);
                }

                if(InsectWarningTypeEnum.MONTH.getValue().equals(record.getInsectWarningType())){
                    AliyunSmsService.sendInsectMonth(insectPhone,json);
                }
            }

            String content = record.buildEmailContent();
            mailService.sendSimpleMail(insectEmail,"虫情预警",content);
        }
    }

}
